package gupao.concurrency.datasync.task;

import gupao.concurrency.datasync.entity.TciWordData;
import gupao.concurrency.datasync.mapper.TciWordMapper;
import gupao.concurrency.datasync.task.v1x.SyncTaskV1;
import gupao.concurrency.datasync.task.v1x.WordProviderMockOpt1;
import gupao.concurrency.datasync.tbapi.Resp;
import gupao.concurrency.datasync.tbapi.TciWordDataApi;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
abstract public class AbstractSyncTask {
    @ToString
    @Getter @Setter
    @RequiredArgsConstructor
    public static class SyncTaskStatus {
        private static final int ERROR_KEEP_MAX = 3;

        private final Date startTime;
        private Date endTime;

        private long wordProvideTimeCost;
        private long syncTimeCost;
        private long totalTimeCost;

        private final AtomicLong succNum = new AtomicLong(0);
        private final AtomicLong errorNum = new AtomicLong(0);
        private final String[] last3Error = new String[ERROR_KEEP_MAX];
        private final AtomicInteger errorIndex = new AtomicInteger(0);

        public void addSuccess(long succ) {
            succNum.addAndGet(succ);
        }
        public void addFail(long fail) {
            errorNum.addAndGet(fail);
        }
        public void addError(String error) {
            for ( ; ; ) {
                int curIndex = errorIndex.get();
                int updateIndex = (curIndex + 1) % ERROR_KEEP_MAX;
                if (errorIndex.compareAndSet(curIndex, updateIndex)) {
                    last3Error[curIndex] = error;
                    break;
                }
            }
        }
    }

    protected
    ConcurrentHashMap<Integer,InnerTaskResultWrapper>
            taskResultHolder = new ConcurrentHashMap<>();
    @Getter
    @AllArgsConstructor
    protected final class InnerTaskResultWrapper{
        private final String lastError;
        private final long succ;
        private final long fail;
    }
    protected final class InnerTaskOpt extends InnerTask{
        private String lastError;
        private long succ = 0, fail = 0;
        public InnerTaskOpt(int number, List<String> wordList){
            super(number, wordList, null);
        }

        private void batchInsert(List<TciWordData> batch){
            int x = tciWordMapper.insert(batch);
            if (x > 0) {
                succ += x;
            }
            if( x < batch.size() ){
                fail += batch.size() - x;
            }
            batch.clear();
        }

        @Override
        public void run() {
            log.info("SyncTask#{} start running by thread: {}",
                    number, Thread.currentThread().getName());
            int batchSize = 20;
            List<TciWordData> batchInserts = new ArrayList<>();
            for (String word : wordList) {
                Resp resp = api.syncTciWordReport(word);
                if (resp.isSuccess() && resp.getData() != null) {
                    /*List<TciWordData> data = new ArrayList<>();
                    data.add(resp.getData());
                    int x = tciWordMapper.insert(data);
                    if (x > 0) {
                        succ += x;
                    }*/
                    batchInserts.add(resp.getData());
                } else {
                    fail++;
                    lastError = resp.getMsg();
                }
                if(batchInserts.size() == batchSize){
                    batchInsert(batchInserts);
                }
            }
            if(batchInserts.size() > 0){
                batchInsert(batchInserts);
            }
            taskResultHolder.put(number,
                    new InnerTaskResultWrapper(lastError,succ,fail));
            log.info("SyncTask#{} finished by thread: {}",
                    number, Thread.currentThread().getName());
        }
    }

    @AllArgsConstructor
    protected class InnerTask implements Runnable {
        protected int number; //任务编号
        protected List<String> wordList;
        protected SyncTaskV1.SyncTaskStatus status;
        @Override
        public void run() {
            log.info("SyncTask#{} start running by thread: {}",number, Thread.currentThread().getName());
            for (String word : wordList) {
                Resp resp = api.syncTciWordReport(word);
                if (resp.isSuccess() && resp.getData() != null) {
                    List<TciWordData> data = new ArrayList<>();
                    data.add(resp.getData());
                    int x = tciWordMapper.insert(data);
                    if (x > 0) {
                        status.addSuccess(x);
                    }
                } else {
                    status.addFail(1);
                    status.addError(resp.getMsg());
                }
            }
            log.info("SyncTask#{} finished by thread: {}",number, Thread.currentThread().getName());
        }
    }

    @Autowired
    protected TciWordDataApi api;
    @Autowired
    protected TciWordMapper tciWordMapper;

    protected AtomicBoolean start = new AtomicBoolean(false);

    @Getter
    protected volatile SyncTaskStatus status;

}
